﻿using System;
using System.Data.Entity;
using System.Linq;
using System.Threading.Tasks;
using Abp.Application.Services.Dto;
using Abp.Authorization;
using Abp.AutoMapper;
using Abp.Domain.Repositories;
using Abp.Domain.Uow;
using Abp.Linq.Extensions;
using Abp.Runtime.Session;
using Abp.UI;
using Microsoft.AspNet.Identity;
using Microsoft.Extensions.Internal;
using Microsoft.Owin.Security;
using Pay.WxPay;
using SingleUserMall.Authorization;
using SingleUserMall.Authorization.Roles;
using SingleUserMall.Authorization.Users;
using SingleUserMall.Common;
using SingleUserMall.Orders;
using SingleUserMall.Points;
using SingleUserMall.Users.Form;
using SingleUserMall.Users.VO;

namespace SingleUserMall.Users
{
    public class UserManageAppService : SingleUserMallAppServiceBase, IUserManageAppService
    {
        private readonly IRepository<Role> _roleRepository;
        private readonly IRepository<User, long> _userRepository;
        private readonly IRepository<UserCommission, long> _userCommissionRepository;
        private readonly IRepository<UserCash, long> _userCashRepository;
        private readonly IRepository<UserSale, long> _userSaleRepository;
        private readonly IRepository<UserRefit, long> _userRefitRepository;
        private readonly IRepository<UserPromotion, long> _userPromotionRepository;
        private readonly IRepository<UserRedPacketDetail, long> _userRedPacketDetailRepository;
        private readonly IRepository<UserWalletDetail, long> _userWalletDetailRepository;
        private readonly IRepository<Order, long> _orderRepository;
        private readonly IRepository<UserPoints, long> _userPointRepository;
        public OrderManager OrderManager { get; set; }

        public UserManageAppService(
            IRepository<Role> roleRepository,
            IRepository<User, long> userRepository,
            IRepository<UserCommission, long> userCommissionRepository,
            IRepository<UserCash, long> userCashRepository,
            IRepository<UserSale, long> userSaleRepository,
            IRepository<UserRefit, long> userRefitRepository,
            IRepository<UserPromotion, long> userPromotionRepository,
            IRepository<UserRedPacketDetail, long> userRedPacketDetailRepository,
            IRepository<UserWalletDetail, long> userWalletDetailRepository,
            IRepository<Order, long> orderRepository,
            IRepository<UserPoints, long> userPointRepository
            )
        {
            _roleRepository = roleRepository;
            _userRepository = userRepository;
            _userCommissionRepository = userCommissionRepository;
            _userCashRepository = userCashRepository;
            _userSaleRepository = userSaleRepository;
            _userRefitRepository = userRefitRepository;
            _userPromotionRepository = userPromotionRepository;
            _userRedPacketDetailRepository = userRedPacketDetailRepository;
            _userWalletDetailRepository = userWalletDetailRepository;
            _orderRepository = orderRepository;
            _userPointRepository = userPointRepository;
        }
        [AbpAuthorize]
        public async Task<PagedResultDto<AdminVO>> GetAdminsAsync(UserSearchForm form)
        {
            var query = _userRepository.GetAll().Where(x => x.IsAdmin)
                .WhereIf(!string.IsNullOrEmpty(form.Keywords), x => x.PhoneNumber.Contains(form.Keywords)
                 || x.UserName.Contains(form.Keywords) || x.Name.Contains(form.Keywords))
                 .OrderByDescending(x => x.CreationTime);
            var result = await query.ToPagedResultDtoAsync<User, AdminVO>(form, (u, vo) =>
            {
                vo.RoleNames = UserManager.GetRoles(u.Id);
            });
            return result;
        }
        [AbpAuthorize]
        public async Task<PagedResultDto<UserVO>> GetUsersAsync(UserSearchForm form)
        {
            var query = _userRepository.GetAll().Where(x => !x.IsAdmin)
                .WhereIf(!string.IsNullOrEmpty(form.Keywords), x => x.PhoneNumber.Contains(form.Keywords)
                 || x.UserName.Contains(form.Keywords) || x.Name.Contains(form.Keywords))
                 .WhereIf(form.VipLevel.HasValue, x => x.VipLevel == form.VipLevel)
                 .OrderByDescending(x => x.CreationTime);
            return await query.ToPagedResultDtoAsync<User, UserVO>(form);
        }

        [AbpAuthorize]
        public async Task ChangeUsersWalletAsync(UserSearchForm form)
        {
            var query = _userRepository.GetAll().Where(x => !x.IsAdmin)
                .WhereIf(!string.IsNullOrEmpty(form.Keywords), x => x.PhoneNumber.Contains(form.Keywords) || x.UserName.Contains(form.Keywords) || x.Name.Contains(form.Keywords))
                .WhereIf(form.VipLevel.HasValue, x => x.VipLevel == form.VipLevel)
                .OrderByDescending(x => x.CreationTime).ToList();
            query.ForEach(user =>
            {
                user.UserWallet += form.Amount.Value;
                _userWalletDetailRepository.Insert(new UserWalletDetail
                {
                    UserId = user.Id,
                    WalletExchangeAmount = form.Amount.Value,
                    WalletExchangeReason = form.Amount >= 0 ? $"后台充值{form.Amount}元" : $"后台扣除{form.Amount}元",
                    WalletExchangeTime = DateTime.Now,
                    WalletType = form.Amount >= 0 ? UserWalletType.In : UserWalletType.Out
                });
            });
        }

        public async Task<AdminVO> LoginAsync(LoginForm form)
        {
            var loginResult = await LogInManager.LoginAsync(form.UserName, form.Password, null, false);
            if (loginResult.Result != AbpLoginResultType.Success)
            {
                throw CreateExceptionForFailedLoginAttempt(loginResult.Result, form.UserName);
            }
            if (!loginResult.User.IsAdmin)
            {
                throw new UserFriendlyException("此用户没有管理权限");
            }
            var identity = await UserManager.CreateIdentityAsync(loginResult.User, DefaultAuthenticationTypes.ExternalBearer);
            var ticket = new AuthenticationTicket(identity, new AuthenticationProperties());
            var currentUtc = new SystemClock().UtcNow;
            ticket.Properties.IssuedUtc = currentUtc;
            ticket.Properties.ExpiresUtc = currentUtc.Add(TimeSpan.FromDays(30));
            var token = OAuthBearerOptions.AccessTokenFormat.Protect(ticket);
            var permissions = await UserManager.GetGrantedPermissionsAsync(loginResult.User);
            return loginResult.User.ToVO<User, AdminVO>((u, vo) =>
            {
                vo.Token = token;
                vo.PermissionNames = permissions.Select(x => x.Name).ToList();
            });
        }


        [AbpAuthorize]
        public async Task RemoveAsync(SingleId<long> form)
        {
            await _userRepository.DeleteAsync(form.Id);
        }
        [AbpAuthorize]
        public async Task<string> ResetPasswordAsync(SingleId<long> form)
        {
            var user = await _userRepository.FirstOrDefaultAsync(form.Id);
            user.Password = new PasswordHasher().HashPassword(User.DefaultPassword);
            return User.DefaultPassword;
        }
        [AbpAuthorize]
        public async Task SaveAdminAsync(AdminForm form)
        {
            var hasAdmin = await _userRepository.CountAsync(x => x.UserName == form.UserName && x.Id != form.Id) > 0;
            if (hasAdmin)
            {
                throw new UserFriendlyException("已存在该用户名");
            }
            var user = await UserManager.FindByIdAsync(form.Id);
            if (user != null)
            {
                user = form.MapTo(user);
                user.Surname = user.Name;
                user.IsAdmin = true;
                user.EmailAddress = $"{user.UserName}@singleusermall.com";
                await _userRepository.UpdateAsync(user);
                await CurrentUnitOfWork.SaveChangesAsync();
                await UserManager.SetRoles(user, form.RoleNames.ToArray());
            }
            else
            {
                user = form.MapTo<User>();
                user.Surname = user.Name;
                user.IsAdmin = true;
                user.IsActive = true;
                user.EmailAddress = $"{user.UserName}@singleusermall.com";
                user.Password = new PasswordHasher().HashPassword(User.DefaultPassword);
                var userId = await _userRepository.InsertAndGetIdAsync(user);
                await CurrentUnitOfWork.SaveChangesAsync();
                await UserManager.AddToRolesAsync(userId, form.RoleNames.ToArray());
            }
        }
        [AbpAuthorize]
        public async Task SetActiveAsync(ActiveForm form)
        {
            var user = await _userRepository.FirstOrDefaultAsync(form.Id);
            if (user != null)
            {
                user.IsActive = form.IsActive;
            }
        }
        [AbpAuthorize]
        public async Task UpdatePasswordAsync(UpdatePasswordForm form)
        {
            var user = await _userRepository.FirstOrDefaultAsync(AbpSession.GetUserId());
            if (new PasswordHasher().VerifyHashedPassword(user.Password, form.OldPassword) == PasswordVerificationResult.Success)
            {
                user.Password = new PasswordHasher().HashPassword(form.Password);
            }
            else
            {
                throw new UserFriendlyException("旧密码不正确");
            }
        }
        [AbpAuthorize]
        public async Task<PagedResultDto<UserCommissionVO>> GetUserCommisionsAsync(UserPagedForm form)
        {
            var userCommisionsQuery = _userCommissionRepository.GetAll().Where(x => x.UserId == form.UserId)
                .OrderByDescending(x => x.CreationTime);
            return await userCommisionsQuery.ToPagedResultDtoAsync<UserCommission, UserCommissionVO>(form, (c, vo) =>
            {
                vo.inFromUser = _userRepository.FirstOrDefault(c.FromUserId);
            });
        }

        [AbpAuthorize]
        public async Task<PagedResultDto<UserRedPacketVO>> GetUserRedPacketAsync(UserPagedForm form)
        {
            var query = _userRedPacketDetailRepository.GetAll().Where(x => x.UserId == form.UserId)
                .OrderByDescending(x => x.ExchangeTime);
            return await query.ToPagedResultDtoAsync<UserRedPacketDetail, UserRedPacketVO>(form, (c, vo) =>
            {

            });
        }

        [AbpAuthorize]
        public async Task<PagedResultDto<UserCashVO>> GetUserCashesAsync(UserPagedForm form)
        {
            var userCashesQuery = _userCashRepository.GetAll().Where(x => x.UserId == form.UserId && x.VerifyStatus == UserCashVerifyStatus.Audited)
                .OrderByDescending(x => x.CreationTime)
                .ThenBy(x => x.CashType);
            return await userCashesQuery.ToPagedResultDtoAsync<UserCash, UserCashVO>(form);
        }


        [AbpAuthorize]
        public async Task<PagedResultDto<UserCashVO>> GetAllUserCashesAsync(UserCashVerifyPagedForm form)
        {
            var userCashesQuery = _userCashRepository.GetAll().WhereIf(form.VerifyStatus.HasValue, x => x.VerifyStatus == form.VerifyStatus)
                .WhereIf(!string.IsNullOrEmpty(form.Keywords), x => x.User.PhoneNumber.Contains(form.Keywords)
                 || x.User.UserName.Contains(form.Keywords) || x.User.Name.Contains(form.Keywords))
                .OrderByDescending(x => x.CreationTime)
                .ThenBy(x => x.CashType);
            return await userCashesQuery.ToPagedResultDtoAsync<UserCash, UserCashVO>(form, (o, vo) =>
             {
                 vo.Name = o.User.Name;
                 vo.PhoneNumber = o.User.PhoneNumber;
             });
        }

        [AbpAuthorize]
        public async Task<string> CashAuditAsync(UserCashAuditForm form)
        {
            bool success = false;
            var userCash = await _userCashRepository.FirstOrDefaultAsync(form.Id);
            userCash.VerifyStatus = form.IsPass ? UserCashVerifyStatus.Audited : UserCashVerifyStatus.Rejected;
            var user = await _userRepository.FirstOrDefaultAsync(userCash.UserId);
            if (form.IsPass)
            {
                //暂时关闭微信打款
                //success = WxPayContext.H5Instance.PayBank(userCash.OrderNo, userCash.CardNumber, userCash.CardName, userCash.BankCode, userCash.Amount * 0.82M);
                if (success)
                {
                    userCash.Status = CashStatus.Processing;
                    if (userCash.CashType == CashType.Commision)
                    {
                        user.Commision -= userCash.Amount;
                    }
                    else if (userCash.CashType == CashType.RedPacket)
                    {
                        user.UserRedPacket -= userCash.Amount;
                    }
                    else if (userCash.CashType == CashType.CanUsePoint)
                    {
                        user.CanUsePoints -= userCash.Amount;
                    }
                    return "审批成功，佣金已经提现到银行卡，请等待到账";
                }
                else
                {
                    userCash.Status = CashStatus.Success;
                    if (userCash.CashType == CashType.Commision)
                    {
                        user.Commision -= userCash.Amount;
                    }
                    else if (userCash.CashType == CashType.RedPacket)
                    {
                        user.UserRedPacket -= userCash.Amount;
                    }
                    else if (userCash.CashType == CashType.CanUsePoint)
                    {
                        user.CanUsePoints -= userCash.Amount;
                    }
                    return "审批成功，请手动转账";
                }
            }
            return "未通过审核";
        }

        [AbpAuthorize]
        public async Task<PagedResultDto<UserVO>> GetSpreadUsersAsync(UserSpreadPagedForm form)
        {
            var spreadUserQuery = _userRepository.GetAll()
                .WhereIf(form.Level == SpreadLevel.Source, x => x.SourceUserId == form.UserId)
                .WhereIf(form.Level == SpreadLevel.Grand, x => x.GrandUserId == form.UserId)
                .OrderByDescending(x => x.CreationTime);
            return await spreadUserQuery.ToPagedResultDtoAsync<User, UserVO>(form);
        }

        [AbpAuthorize]
        public async Task<UserVO> GetUserAsync(SingleId<long> form)
        {
            var user = await _userRepository.FirstOrDefaultAsync(form.Id);
            return user.ToVO<User, UserVO>();
        }
        [AbpAuthorize]
        public async Task<PagedResultDto<UserPromotionVO>> GetUserPromotionsAsync(UserPromotionPagedForm form)
        {
            var query = _userPromotionRepository.GetAll()
                .WhereIf(form.Status.HasValue, x => x.Status == form.Status)
                .OrderByDescending(x => x.CreationTime);
            return await query.ToPagedResultDtoAsync<UserPromotion, UserPromotionVO>(form);
        }
        [AbpAuthorize]
        public async Task PromotionAuditAsync(UserPromotionAuditForm form)
        {
            var userPromotion = await _userPromotionRepository.FirstOrDefaultAsync(form.Id);
            userPromotion.Status = form.IsPass ? VerifyStatus.Audited : VerifyStatus.Rejected;
            userPromotion.Description = form.Description;
            var user = await _userRepository.FirstOrDefaultAsync(userPromotion.UserId);
            if (form.IsPass)
                user.IsPromotion = true;
        }

        [AbpAuthorize]
        public async Task<PagedResultDto<UserSaleVO>> GetUserSalesAsync(UserSalePagedForm form)
        {
            var query = _userSaleRepository.GetAll()
                .WhereIf(form.Disposed.HasValue, x => x.Disposed == form.Disposed)
                .OrderByDescending(x => x.CreationTime);
            return await query.ToPagedResultDtoAsync<UserSale, UserSaleVO>(form);
        }
        [AbpAuthorize]
        public async Task<PagedResultDto<UserRefitVO>> GetUserRefitsAsync(UserRefitPagedForm form)
        {
            var query = _userRefitRepository.GetAll()
                .WhereIf(form.Disposed.HasValue, x => x.Disposed == form.Disposed)
                .OrderByDescending(x => x.CreationTime);
            return await query.ToPagedResultDtoAsync<UserRefit, UserRefitVO>(form);
        }
        [AbpAuthorize]
        public async Task UserSaleDisposeAsync(SingleId<long> form)
        {
            var userSale = await _userSaleRepository.FirstOrDefaultAsync(form.Id);
            userSale.Disposed = true;
        }
        [AbpAuthorize]
        public async Task UserRefitDisposeAsync(SingleId<long> form)
        {
            var userRefit = await _userRefitRepository.FirstOrDefaultAsync(form.Id);
            userRefit.Disposed = true;
        }
        [AbpAuthorize]
        public async Task ReCashAsync(SingleId<long> form)
        {
            var userCash = await _userCashRepository.FirstOrDefaultAsync(form.Id);
            UserManager.Cash(userCash);
        }
        [AbpAuthorize]
        public async Task TestPayComplete(string orderNo)
        {
            OrderManager.PayComplete(orderNo, 0);
        }
        [AbpAuthorize]
        public async Task TestRefund(long id)
        {
            OrderManager.Refund(id);
        }
        [AbpAuthorize]
        public async Task WalletChargeAsync(WalletForm form)
        {
            var user = await UserManager.GetUserByIdAsync(form.UserId.Value);
            if (user.UserWallet + form.Amount < 0)
                throw new UserFriendlyException("钱包剩余金额不能为负数");
            _userWalletDetailRepository.Insert(new UserWalletDetail
            {
                UserId = user.Id,
                WalletExchangeAmount = form.Amount,
                WalletExchangeReason = form.Amount >= 0 ? $"后台充值{form.Amount}元" : $"后台扣除{form.Amount}元",
                WalletExchangeTime = DateTime.Now,
                WalletType = form.Amount >= 0 ? UserWalletType.In : UserWalletType.Out
            });
            user.UserWallet += form.Amount;
        }

        [AbpAuthorize]
        public async Task UserLevelChangeAsync(UserVipLevelForm form)
        {
            var user = await UserManager.GetUserByIdAsync(form.UserId.Value);
            user.VipLevel = form.VipLevel;
            user.IsVip = form.VipLevel > 0;
        }

        [AbpAuthorize]
        public async Task<UserMiniVO> AddNewUserAsync(AddUserForm form)
        {
            var user = _userRepository.FirstOrDefault(x => x.PhoneNumber == form.PhoneNumber);
            if (user != null)
            {
                throw new UserFriendlyException("存在重复的手机号，不能添加新用户");
            }
            else
            {
                try
                {
                    user = new User
                    {
                        Name = form.PhoneNumber,
                        Avatar = "",
                        Gender = Authorization.Users.Gender.Male,
                        IsActive = true,
                        OpenId = "",
                        Surname = form.PhoneNumber,
                        EmailAddress = "user@singleusermall.com",
                        Password = new PasswordHasher().HashPassword(User.DefaultPassword),
                        VipLevel = form.VipLevel,
                        IsVip = form.VipLevel > 0,
                        PhoneNumber = form.PhoneNumber,
                        UserIncome = User.UserIncomeStatus.MiddleIncome,
                        UserName = form.PhoneNumber,
                        AgencyLevel = 0
                    };
                    var userId = await _userRepository.InsertAndGetIdAsync(user);
                    await CurrentUnitOfWork.SaveChangesAsync();
                    user = await _userRepository.FirstOrDefaultAsync(userId);
                }

                catch (Exception e)
                {

                }
            }
            var result = user.ToVO<User, UserMiniVO>();
            result.Token = await CreateTokenAsync(user);
            return result;
        }

        public async Task<PagedResultDto<UserDividendsVO>> GetAllUserDividendsAsync(UserSearchForm form)
        {
            var query = _userRepository.GetAll().Where(x => !x.IsAdmin)
                 .WhereIf(!string.IsNullOrEmpty(form.Keywords), x => x.Name.Contains(form.Keywords))
                 .WhereIf(!string.IsNullOrEmpty(form.Keywords), x => x.PhoneNumber.Contains(form.Keywords))
                 .OrderByDescending(x => x.SumConsumptionAmount);
            return await query.ToPagedResultDtoAsync<User, UserDividendsVO>(form, (u, uo) => { });
        }

        public async Task<PagedResultDto<UserDividendVO>> GetAllUserDividendAsync(UserPagedForm form)
        {
            var query = _orderRepository.GetAll().Where(x => x.ShoppingCartType == ShoppingCarts.ShoppingCartType.TreeShopping && x.UserId == form.UserId && x.Status == OrderStatus.Paid && x.DividendEndTime < DateTime.Now)
                .OrderByDescending(x => x.CreationTime);
            return await query.ToPagedResultDtoAsync<Order, UserDividendVO>(form, (o, uo) =>
            {
                uo.inFromUser = _userRepository.FirstOrDefault(o.UserId);
                uo.Avatar = o.User.Avatar;
                uo.Name = o.User.Name;
                var orderDetail = o.OrderDetails.FirstOrDefault();
                uo.ItemName = orderDetail?.ItemSpec?.Item?.Name;
                uo.Amount = o.ActualAmount;
                uo.Timelimit = orderDetail?.ItemSpec?.Item?.Timelimit ?? 0;
                uo.DividendAmountView = ((int)(orderDetail?.ItemSpec?.Item?.DividendAmount * 100)).ToString();
                if (orderDetail?.ItemSpec?.Item?.Timelimit > 0)
                {
                    uo.DividendAmountViewByYear = ((int)(orderDetail?.ItemSpec?.Item?.DividendAmount * 100 / 12 * orderDetail?.ItemSpec?.Item?.Timelimit)).ToString();
                }

                uo.DividendTypes = orderDetail?.ItemSpec?.Item?.DividendTypes;
                uo.Profit = orderDetail?.Profit ?? 0;
                uo.DividendDay = orderDetail?.DividendDay ?? 0;
                uo.PayTime = o.PayTime;
            });
        }
        [AbpAuthorize]
        public async Task<PagedResultDto<UserPointsVO>> GetUserPointsAsync(UserPointPagedForm form)
        {
            
            var query = _userPointRepository.GetAll()
                .WhereIf(form.UserId.HasValue, x=> x.UserId == form.UserId)
                .WhereIf(!string.IsNullOrEmpty(form.Keywords), x=> x.User.Name.Contains(form.Keywords) || x.User.PhoneNumber.Contains(form.Keywords))
                .WhereIf(form.UserPointsStatus.HasValue, x=> x.Status == form.UserPointsStatus)
                .WhereIf(form.UserPointsType.HasValue, x=> x.Type == form.UserPointsType)
                .OrderByDescending(x => x.CreationTime).ThenBy(x => x.Type);
            return await query.ToPagedResultDtoAsync<UserPoints, UserPointsVO>(form, (v, vo) =>
            {
                vo.inFromUser = _userRepository.FirstOrDefault(v.FromUserId);
                vo.inUser = v.User;
            });
        }
        [AbpAuthorize]
        public async Task<PagedResultDto<UserPointsVO>> GetAllUserPointsAsync(UserPointPagedForm form)
        {
            var query = _userPointRepository.GetAll()
                .WhereIf(!string.IsNullOrEmpty(form.Keywords), x => x.User.Name.Contains(form.Keywords) || x.User.PhoneNumber.Contains(form.Keywords))
                .WhereIf(form.UserPointsStatus.HasValue, x => x.Status == form.UserPointsStatus)
                .WhereIf(form.UserPointsType.HasValue, x => x.Type == form.UserPointsType)
                .OrderByDescending(x => x.CreationTime).ThenBy(x => x.Type);
            return await query.ToPagedResultDtoAsync<UserPoints, UserPointsVO>(form, (v, vo) =>
            {
                vo.inFromUser = _userRepository.FirstOrDefault(v.FromUserId);
                vo.inUser = v.User;
            });
        }
    }
}
